#ifndef SCENE_HPP
#define SCENE_HPP

#include <list>
#include "algebra.hpp"
#include "primitive.hpp"
#include "material.hpp"

class SceneNode {
public:
  SceneNode(const std::string& name);
  virtual ~SceneNode();

  virtual void walk_gl(bool picking = false) const;
virtual void reset_joints();

  const Matrix4x4& get_transform() const { return m_trans; }
  const Matrix4x4& get_inverse() const { return m_invtrans; }
  
void highlight_children();
void set_pick();
bool get_pick();
int get_id();

  void set_transform(const Matrix4x4& m)
  {
    m_trans = m;
    m_invtrans = m.invert();
  }

  void set_transform(const Matrix4x4& m, const Matrix4x4& i)
  {
    m_trans = m;
    m_invtrans = i;
  }

  void add_child(SceneNode* child)
  {
    m_children.push_back(child);
	child->set_parent(this);
  }

  void remove_child(SceneNode* child)
  {
    m_children.remove(child);
  }

	void set_parent(SceneNode* parent)
	{
		m_parent = parent;
	}
	SceneNode* get_parent()
	{
		return m_parent;
	}
  // Callbacks to be implemented.
  // These will be called from Lua.
  void rotate(char axis, double angle);
  void scale(const Vector3D& amount);
  void translate(const Vector3D& amount);

  // Returns true if and only if this node is a JointNode
  virtual bool is_joint() const;
  
protected:
  
  // Useful for picking
  int m_id;
  std::string m_name;

  // Transformations
  Matrix4x4 m_trans;
  Matrix4x4 m_invtrans;
	
	// parent
	SceneNode *m_parent;
	// pick inidicator
	bool pick;
	
  // Hierarchy
  typedef std::list<SceneNode*> ChildList;
  ChildList m_children;
};

class JointNode : public SceneNode {
public:
  JointNode(const std::string& name);
  virtual ~JointNode();
  
  virtual void walk_gl(bool bicking = false) const;
virtual void reset_joints();
  virtual bool is_joint() const;

  void set_joint_x(double min, double init, double max);
  void set_joint_y(double min, double init, double max);
void rotate_x(double angle);
void rotate_y(double angle);
double get_joint_x();
double get_joint_y();
  struct JointRange {
    double min, init, max;
  };
protected:
	double current_x;
	double current_y;
  JointRange m_joint_x, m_joint_y;
};

class GeometryNode : public SceneNode {
public:
  GeometryNode(const std::string& name,
               Primitive* primitive);
  virtual ~GeometryNode();

  virtual void walk_gl(bool picking = false) const;

  const Material* get_material() const;
  Material* get_material();

  void set_material(Material* material)
  {
    m_material = material;
  }

protected:
  Material* m_material;
  Primitive* m_primitive;
};

class NodeNameID{
private:
	int m_id;
	SceneNode* m_sn;
public:
	void setNodeNameID(int id, SceneNode* sn)
	{
		m_id = id;
		m_sn = sn;
	}
	SceneNode *getNode()
	{
		return m_sn;
	}
};

#endif
